﻿// -----------------------------------------------------------------------
// <copyright file="HistoOperation.cs" company="FCIS">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace IPPackage.ImageOperation
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class HistoOperation : Operation
    {
        /// <summary>
        /// object to use comman methods insert HistoOperation
        /// </summary>
       private IP_Package.Global_applications.Global_methods_user methods = new IP_Package.Global_applications.Global_methods_user();

        /// <summary>
        /// Gets the min value in array.
        /// </summary>
        /// <param name="data">The data array.</param>
        /// <returns>the min. value</returns>
        public int GetMin(long[] data)
        {
            int min = data.Length;
            try
            {
                for (int i = 0; i < data.Length; i++)
                {
                    if (data[i] > 0)
                    {
                        return i;
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
            }

            return min;
        }

        /// <summary>
        /// Gets the max value in array.
        /// </summary>
        /// <param name="data">The data array.</param>
        /// <returns>the max. value</returns>
        public int GetMax(long[] data)
        {
            int max = 0;
            try
            {
                for (int i = 0; i < data.Length; i++)
                {
                    if (data[i] > 0)
                    {
                        max = i;
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
            }

            return max;
        }

        /// <summary>
        /// Britnesses the specified image.
        /// </summary>
        /// <param name="offset">The offset.</param>
        /// <returns>NEW IMAGE</returns>
        public Bitmap Britness(int offset)
        {
            Bitmap new_ima;
            try
            {
                this.NewBufferOfImage = new Color[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1)];
                new_ima = new Bitmap(this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1));
                for (int i = 0; i < this.BufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.BufferOfImage.GetLength(0); j++)
                    {
                        Color temp = this.BufferOfImage[j, i];
                        int red = (int)temp.R + offset;
                        int green = (int)temp.G + offset;
                        int blue = (int)temp.B + offset;
                        if (red > 255)
                        {
                            red = 255;
                        }
                        else if (red < 0)
                        {
                            red = 0;
                        }

                        if (green > 255)
                        {
                            green = 255;
                        }
                        else if (green < 0)
                        {
                            green = 0;
                        }

                        if (blue > 255)
                        {
                            blue = 255;
                        }
                        else if (blue < 0)
                        {
                            blue = 0;
                        }

                        this.NewBufferOfImage[j, i] = Color.FromArgb(red, green, blue);
                        new_ima.SetPixel(j, i, Color.FromArgb(red, green, blue));
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw ex;
            }

            return new_ima;
        }

        /// <summary>
        /// Gammas the specified image.
        /// </summary>
        /// <param name="gamma">The gamma value.</param>
        /// <returns>new image</returns>
        public Bitmap Gamma(float gamma)
        {
            try
            {
                double[,] gammaRedBuffer = new double[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
                double[,] gammaGreenBuffer = new double[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
                double[,] gammaBlueBuffer = new double[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
                for (int i = 0; i < BufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < BufferOfImage.GetLength(0); j++)
                    {
                        Color temp = BufferOfImage[j, i];
                        gammaRedBuffer[j, i] = Math.Pow(temp.R, gamma);
                        gammaGreenBuffer[j, i] = Math.Pow(temp.G, gamma);
                        gammaBlueBuffer[j, i] = Math.Pow(temp.B, gamma);
                    }
                }

                this.methods.BufferOfImage = this.BufferOfImage;
                Bitmap resultImg = this.methods.Normalization(gammaRedBuffer, gammaGreenBuffer, gammaBlueBuffer);
                this.NewBufferOfImage = this.methods.NewBufferOfImage;
                return resultImg;
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw ex;
            }
        }

        /// <summary>
        /// Contrasts the specified offset.
        /// </summary>
        /// <param name="offset">The offset.</param>
        /// <param name="gragh">The gragh.</param>
        /// <returns>the new image</returns>
        public Bitmap Contrast(int offset, Histogram gragh)
        {
            try
            {
                long[] histogram = gragh.HistoGray();
                double oldMax = this.GetMax(histogram);
                double oldMin = this.GetMin(histogram);
                int newMax = (int)oldMax + (offset / 2);
                int newMin = (int)oldMin - (offset / 2);
                if (newMax > 255)
                {
                    newMax = 255;
                }
                else if (newMin < 0)
                {
                    newMin = 0;
                }

                this.NewBufferOfImage = new Color[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1)];
                Bitmap newImage = new Bitmap(this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1));
                for (int i = 0; i < newImage.Height; i++)
                {
                    for (int j = 0; j < newImage.Width; j++)
                    {
                        Color temp = this.BufferOfImage[j, i];
                        double red = ((((int)temp.R - oldMin) / (oldMax - oldMin)) * (newMax - newMin)) + newMin;
                        double green = ((((int)temp.G - oldMin) / (oldMax - oldMin)) * (newMax - newMin)) + newMin;
                        double blue = ((((int)temp.B - oldMin) / (oldMax - oldMin)) * (newMax - newMin)) + newMin;
                        if (red > 255)
                        {
                            red = 255;
                        }
                        else if (red < 0)
                        {
                            red = 0;
                        }

                        if (green > 255)
                        {
                            green = 255;
                        }
                        else if (green < 0)
                        {
                            green = 0;
                        }

                        if (blue > 255)
                        {
                            blue = 255;
                        }
                        else if (blue < 0)
                        {
                            blue = 0;
                        }

                        this.NewBufferOfImage[j, i] = Color.FromArgb((int)red, (int)green, (int)blue);
                        newImage.SetPixel(j, i, Color.FromArgb((int)red, (int)green, (int)blue));
                    }
                }

                return newImage;
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw ex;
            }
        }

        /// <summary>
        /// Equalizations image.
        /// </summary>
        /// <returns>new image</returns>
        public Bitmap Equalization()
        {
            try
            {
                double[] redCumm = new double[255];
                double[] greenCumm = new double[255];
                double[] blueCumm = new double[255];
                this.HistEqual(ref redCumm, ref greenCumm, ref blueCumm);
                this.NewBufferOfImage = new Color[BufferOfImage.GetLength(0), BufferOfImage.GetLength(1)];
                Bitmap newImg = new Bitmap(BufferOfImage.GetLength(0), BufferOfImage.GetLength(1));
                for (int i = 0; i < BufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < BufferOfImage.GetLength(0); j++)
                    {
                        int newRed = (int)redCumm[BufferOfImage[j, i].R];
                        int newGreen = (int)redCumm[BufferOfImage[j, i].G];
                        int newBlue = (int)redCumm[BufferOfImage[j, i].B];
                        this.NewBufferOfImage[j, i] = Color.FromArgb(newRed, newGreen, newBlue);
                        newImg.SetPixel(j, i, Color.FromArgb(newRed, newGreen, newBlue));
                    }
                }

                return newImg;
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw ex;
            }
        }

        /// <summary>
        /// Gets the MAX color in picture .
        /// </summary>
        /// <param name="data">the array of accurance of certain color in image.</param>
        /// <returns>max color</returns>
        public long GetMaxColor(long[] data)
        {
            long max_color = 0;
            for (int i = 1; i < data.GetLength(0); i++)
            {
                if (data[i] > 0)
                {
                    max_color = i;
                }
            }

            return max_color;
        }

        /// <summary>
        /// Matchings this instance.
        /// </summary>
        /// <param name="img2">The img2.</param>
        /// <returns>MODIFY IMAGE</returns>
        public Bitmap Matching(IPPackage.ImageOperation.Open img2)
        {
            try
            {
                Bitmap newImg = new Bitmap(this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1));
                double[] cumm1R = new double[256];
                double[] cumm1G = new double[256];
                double[] cumm1B = new double[256];
                double[] cumm2R = new double[256];
                double[] cumm2G = new double[256];
                double[] cumm2B = new double[256];
                this.HistEqual(ref cumm1R, ref cumm1G, ref cumm1B);
                this.HistEqual(ref cumm2R, ref cumm2G, ref cumm2B, img2);
                double[] newValueRed = new double[256];
                double[] newValueGreen = new double[256];
                double[] newValueBlue = new double[256];
                for (int i = 0; i < cumm1R.GetLength(0); i++)
                {
                    for (int j = 0; j < cumm2R.GetLength(0); j++)
                    {
                        if (j + 1 != cumm2R.GetLength(0))
                        {
                            if (cumm1R[i] > cumm2R[j] && cumm1R[i] <= cumm2R[j + 1])
                            {
                                double dif1 = cumm1R[i] - cumm2R[j];
                                double dif2 = cumm2R[j + 1] - cumm1R[i];
                                if (dif1 > dif2)
                                {
                                    newValueRed[i] = j + 1;
                                }
                                else
                                {
                                    newValueRed[i] = j;
                                }

                                break;
                            }
                            else if (cumm1R[i] <= cumm2R[j])
                            {
                                newValueRed[i] = j;
                                break;
                            }
                        }
                        else if (j + 1 == cumm2R.GetLength(0))
                        {
                            newValueRed[i] = j;
                        }
                    }
                }

                for (int i = 0; i < cumm1G.GetLength(0); i++)
                {
                    for (int j = 0; j < cumm2G.GetLength(0); j++)
                    {
                        if (j + 1 != cumm2G.GetLength(0))
                        {
                            if (cumm1G[i] > cumm2G[j] && cumm1G[i] <= cumm2G[j + 1])
                            {
                                double dif1 = cumm1G[i] - cumm2G[j];
                                double dif2 = cumm2G[j + 1] - cumm1G[i];
                                if (dif1 > dif2)
                                {
                                    newValueGreen[i] = j + 1;
                                }
                                else
                                {
                                    newValueGreen[i] = j;
                                }

                                break;
                            }
                            else if (cumm1G[i] <= cumm2G[j])
                            {
                                newValueGreen[i] = j;
                                break;
                            }
                        }
                        else if (j + 1 == cumm2G.GetLength(0))
                        {
                            newValueGreen[i] = j;
                        }
                    }
                }

                for (int i = 0; i < cumm1B.GetLength(0); i++)
                {
                    for (int j = 0; j < cumm2B.GetLength(0); j++)
                    {
                        if (j + 1 != cumm2B.GetLength(0))
                        {
                            if (cumm1B[i] > cumm2B[j] && cumm1B[i] <= cumm2B[j + 1])
                            {
                                double dif1 = cumm1B[i] - cumm2B[j];
                                double dif2 = cumm2B[j + 1] - cumm1B[i];
                                if (dif1 > dif2)
                                {
                                    newValueBlue[i] = j + 1;
                                }
                                else
                                {
                                    newValueBlue[i] = j;
                                }

                                break;
                            }
                            else if (cumm1B[i] <= cumm2B[j])
                            {
                                newValueBlue[i] = j;
                                break;
                            }
                        }
                        else if (j + 1 == cumm2B.GetLength(0))
                        {
                            newValueBlue[i] = j;
                        }
                    }
                }

                this.NewBufferOfImage = new Color[this.BufferOfImage.GetLength(0), this.BufferOfImage.GetLength(1)];
                for (int i = 0; i < this.BufferOfImage.GetLength(1); i++)
                {
                    for (int j = 0; j < this.BufferOfImage.GetLength(0); j++)
                    {
                        int r = (int)newValueRed[this.BufferOfImage[j, i].R];
                        int g = (int)newValueGreen[this.BufferOfImage[j, i].G];
                        int b = (int)newValueBlue[this.BufferOfImage[j, i].B];
                        this.NewBufferOfImage[j, i] = Color.FromArgb(r, g, b);
                        newImg.SetPixel(j, i, this.NewBufferOfImage[j, i]);
                    }
                }

                return newImg;
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw ex;
            }
        }

        /// <summary>
        /// Hists the equal.
        /// </summary>
        /// <param name="cumm2R">The cumm2 R.</param>
        /// <param name="cumm2G">The cumm2 G.</param>
        /// <param name="cumm2B">The cumm2 B.</param>
        /// <param name="img2">The img2.</param>
        private void HistEqual(ref double[] cumm2R, ref double[] cumm2G, ref double[] cumm2B, Open img2)
        {
            try
            {
                Histogram his = new Histogram();
                his.BufferOfImage = img2.BufferOfImage;
                long[] red = his.HistoRed();
                long[] green = his.HistoGreen();
                long[] blue = his.HistoBlue();
                long redMax = this.GetMax(red);
                long greenMax = this.GetMax(green);
                long blueMax = this.GetMax(blue);
                cumm2R = new double[redMax + 1];
                cumm2G = new double[greenMax + 1];
                cumm2B = new double[blueMax + 1];
                int i;
                if (blueMax > greenMax)
                {
                    if (redMax > blueMax)
                    {
                        i = (int)redMax;
                    }
                    else
                    {
                        i = (int)blueMax;
                    }
                }
                else
                {
                    if (redMax > greenMax)
                    {
                        i = (int)redMax;
                    }
                    else
                    {
                        i = (int)greenMax;
                    }
                }

                for (int j = 0; j <= i; j++)
                {
                    if (j <= redMax)
                    {
                        if (j == 0)
                        {
                            cumm2R[j] = red[j];
                        }
                        else
                        {
                            cumm2R[j] = cumm2R[j - 1] + red[j];
                        }
                    }

                    if (j <= greenMax)
                    {
                        if (j == 0)
                        {
                            cumm2G[j] = green[j];
                        }
                        else
                        {
                            cumm2G[j] = cumm2G[j - 1] + green[j];
                        }
                    }

                    if (j <= blueMax)
                    {
                        if (j == 0)
                        {
                            cumm2B[j] = blue[j];
                        }
                        else
                        {
                            cumm2B[j] = cumm2B[j - 1] + blue[j];
                        }
                    }
                }

                for (int j = 0; j <= i; j++)
                {
                    if (j <= redMax)
                    {
                        cumm2R[j] = (int)Math.Round((cumm2R[j] / ((double)img2.BufferOfImage.GetLength(0) * img2.BufferOfImage.GetLength(1))) * 255, 3);
                    }

                    if (j <= greenMax)
                    {
                        cumm2G[j] = (int)Math.Round((cumm2G[j] / ((double)img2.BufferOfImage.GetLength(0) * img2.BufferOfImage.GetLength(1))) * 255, 3);
                    }

                    if (j <= blueMax)
                    {
                        cumm2B[j] = (int)Math.Round((cumm2B[j] / ((double)img2.BufferOfImage.GetLength(0) * img2.BufferOfImage.GetLength(1))) * 255, 3);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw ex;
            }
        }

        /// <summary>
        /// Hists the equal.
        /// </summary>
        /// <param name="redCumm">The red cumm.</param>
        /// <param name="greenCumm">The green cumm.</param>
        /// <param name="blueCumm">The blue cumm.</param>
        private void HistEqual(ref double[] redCumm, ref double[] greenCumm, ref double[] blueCumm)
        {
            try
            {
                Histogram his = new Histogram();
                his.BufferOfImage = this.BufferOfImage;
                long[] red = his.HistoRed();
                long[] green = his.HistoGreen();
                long[] blue = his.HistoBlue();
                long redMax = this.GetMax(red);
                long greenMax = this.GetMax(green);
                long blueMax = this.GetMax(blue);
                redCumm = new double[redMax + 1];
                greenCumm = new double[greenMax + 1];
                blueCumm = new double[blueMax + 1];
                int i;
                if (blueMax > greenMax)
                {
                    if (redMax > blueMax)
                    {
                        i = (int)redMax;
                    }
                    else
                    {
                        i = (int)blueMax;
                    }
                }
                else
                {
                    if (redMax > greenMax)
                    {
                        i = (int)redMax;
                    }
                    else
                    {
                        i = (int)greenMax;
                    }
                }

                for (int j = 0; j <= i; j++)
                {
                    if (j <= redMax)
                    {
                        if (j == 0)
                        {
                            redCumm[j] = red[j];
                        }
                        else
                        {
                            redCumm[j] = redCumm[j - 1] + red[j];
                        }
                    }

                    if (j <= greenMax)
                    {
                        if (j == 0)
                        {
                            greenCumm[j] = green[j];
                        }
                        else
                        {
                            greenCumm[j] = greenCumm[j - 1] + green[j];
                        }
                    }

                    if (j <= blueMax)
                    {
                        if (j == 0)
                        {
                            blueCumm[j] = blue[j];
                        }
                        else
                        {
                            blueCumm[j] = blueCumm[j - 1] + blue[j];
                        }
                    }
                }

                for (int j = 0; j <= i; j++)
                {
                    if (j <= redMax)
                    {
                        redCumm[j] = (int)Math.Round((redCumm[j] / ((double)BufferOfImage.GetLength(0) * BufferOfImage.GetLength(1))) * 255, 3);
                    }

                    if (j <= greenMax)
                    {
                        greenCumm[j] = (int)Math.Round((greenCumm[j] / ((double)BufferOfImage.GetLength(0) * BufferOfImage.GetLength(1))) * 255, 3);
                    }

                    if (j <= blueMax)
                    {
                        blueCumm[j] = (int)Math.Round((blueCumm[j] / ((double)BufferOfImage.GetLength(0) * BufferOfImage.GetLength(1))) * 255, 3);
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
                throw ex;
            }
        }
    }
}